/*
 * Tomer Nuni 300585312
 * Idan Meshita 300043726
 */
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;

import javax.swing.JFileChooser;
 


public class MyCanvas extends Canvas implements KeyListener,MouseListener,MouseMotionListener{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private ViewManager viewManager ;
	private TransformationManager transformationManager;
	private SceneManager sceneManger;
	private ClipingManger clipingManger ;
	
	private EdgeByPoints upperBorder ;
	private EdgeByPoints lowerBorder ;
	private EdgeByPoints leftBorder;
	private EdgeByPoints rightBorder;
	private Point centerPoint ;
	
	private  final static char TRANSFORMATION_TRANSLATE='t';
	private  final static char TRANSFORMATION_ROTATE='r';
	private  final static char TRANSFORMATION_SCALE='s';
	private  final static char TRANSFORMATION_NONE='n';
	
	private Point mousePointClicked = null;
	private char transformationType = TRANSFORMATION_NONE;
	private boolean toggleCiping=false;
	private boolean drawLine=false;
	
	private Point linePointStart=null;
	private Point linePointEnd=null;
	
	
	
	public MyCanvas() {
		addMouseMotionListener(this);
		addMouseListener(this);
		addKeyListener(this);
		
	}
	
	public void initCanvas() throws IOException{
		
		
		viewManager = new ViewManager();
		transformationManager = new TransformationManager();
		sceneManger = new SceneManager();
		clipingManger = new ClipingManger();
		
		viewManager.init(Constants.VIEW_FILE_NAME);
		sceneManger.init(Constants.SCENE_FILE_NAME);
		
		
		buildScreen();
	}
	
	private void buildScreen(){
		setSize(viewManager.getResoultionWindowWidth()+Constants.FRAM_POSITION*2, viewManager.getResoultionWindowHeight()+Constants.FRAM_POSITION*2);
		
	}
	@Override
	public void setBounds(int x, int y, int width, int height) {
		super.setBounds(x, y, width, height);
		viewManager.resetResolution(width-Constants.FRAM_POSITION*2,height-Constants.FRAM_POSITION*2);
		centerPoint = new Point((viewManager.getResoultionWindowWidth()+2*Constants.FRAM_POSITION)/2, (viewManager.getResoultionWindowHeight()+2*Constants.FRAM_POSITION)/2);
		
	}
	public void paint(Graphics g) {
		drawFrame(g);
		drawScene(g);
		if (linePointStart!=null && linePointEnd!=null)
			g.drawLine(linePointStart.x, linePointStart.y, linePointEnd.x, linePointEnd.y);
	}

	

	private void drawFrame(Graphics g) {
		if (toggleCiping)
			g.setColor(Color.RED);
		else
			g.setColor(Color.BLUE);
		upperBorder = new EdgeByPoints(new Point(Constants.FRAM_POSITION, Constants.FRAM_POSITION),
				   new Point(viewManager.getResoultionWindowWidth()+Constants.FRAM_POSITION , Constants.FRAM_POSITION));

		lowerBorder = new EdgeByPoints(new Point(Constants.FRAM_POSITION, Constants.FRAM_POSITION+viewManager.getResoultionWindowHeight()),
					new Point(Constants.FRAM_POSITION +viewManager.getResoultionWindowWidth(), Constants.FRAM_POSITION+viewManager.getResoultionWindowHeight()));

		leftBorder = new EdgeByPoints(new Point(Constants.FRAM_POSITION, Constants.FRAM_POSITION),
					new Point(Constants.FRAM_POSITION ,viewManager.getResoultionWindowHeight()+ Constants.FRAM_POSITION));


		rightBorder = new EdgeByPoints(new Point(Constants.FRAM_POSITION+viewManager.getResoultionWindowWidth(), Constants.FRAM_POSITION),
				new Point(Constants.FRAM_POSITION+viewManager.getResoultionWindowWidth() , Constants.FRAM_POSITION+viewManager.getResoultionWindowHeight()));

		g.drawLine(upperBorder.form.x, upperBorder.form.y, upperBorder.to.x, upperBorder.to.y);
		g.drawLine(lowerBorder.form.x, lowerBorder.form.y, lowerBorder.to.x, lowerBorder.to.y);
		g.drawLine(leftBorder.form.x, leftBorder.form.y, leftBorder.to.x, leftBorder.to.y);
		g.drawLine(rightBorder.form.x, rightBorder.form.y, rightBorder.to.x, rightBorder.to.y);

	}
	private void drawScene(Graphics g) {
		g.setColor(Color.BLACK);
		Collection<Edge> edges= sceneManger.getEdges();
		Collection<EdgeByPoints> paintEdges=  new LinkedList<EdgeByPoints>();
		
		//double [][] mat = Matrix.multiplyMatrix(transformationManager.getSelectedTranformationMatix(), transformationManager.getTransformMatrix());
		//mat = Matrix.multiplyMatrix(viewManager.getViewMatix(), mat);

		double [][] mat = Matrix.multiplyMatrix(transformationManager.getTransformMatrix(), viewManager.getViewMatix());
		mat = Matrix.multiplyMatrix( transformationManager.getSelectedTranformationMatix(),mat);

		Point [] p = sceneManger.getPoints();
		for (Edge edge : edges) {
			
			
			Point newFromPoint = Matrix.multiplyMatrix(mat, p[edge.form]);
			Point newToPoint = Matrix.multiplyMatrix(mat, p[edge.to]);
			paintEdges.add(new EdgeByPoints(newFromPoint, newToPoint) );
			
		}
		if (toggleCiping)
			paintEdges = clipingManger.doCliping(paintEdges,upperBorder,lowerBorder,rightBorder,leftBorder);
		
		for (EdgeByPoints edge : paintEdges) {
			g.drawLine(edge.form.x,edge.form.y,edge.to.x,edge.to.y);
		}
		
		
		
	}

	@Override
	public void mouseDragged(MouseEvent arg0) {
		if (drawLine){
			linePointEnd=arg0.getPoint();
			repaint();
			return;
		}
		
		switch (transformationType) {
		case TRANSFORMATION_SCALE:
			transformationManager.createScaleMatrix(mousePointClicked,arg0.getPoint(),centerPoint);
			break;
		case TRANSFORMATION_ROTATE:
			transformationManager.createRotationMatrix(mousePointClicked,arg0.getPoint(),centerPoint);
			break;
		case TRANSFORMATION_TRANSLATE:
			transformationManager.createTranslateMatrix(mousePointClicked,arg0.getPoint());
			break;

		default:
			break;
		}
		repaint();
	}

	@Override
	public void mouseMoved(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		//check if the ctr is on
		if (drawLine){
			linePointStart= e.getPoint();
			return ;
		}
		
		//check limits
		Point p = e.getPoint();
		//System.out.println(p);
		if (p.y > upperBorder.form.y && p.y < lowerBorder.form.y &&
				p.x>leftBorder.form.x && p.x<rightBorder.form.x){
			selectTransformation(p);
		}
			
		mousePointClicked = e.getPoint();
		
	}

	private void selectTransformation(Point p) {

		/*
		 * Divide the screen into 9 square
		 * each square activates different transformation 
		 * R	S	R
		 * S	T	S
		 * R	S	R
		 * 
		 */
		
		mousePointClicked=p;
		
		if ((p.x < ((double)viewManager.getResoultionWindowWidth()/3) &&
				p.y < ((double)viewManager.getResoultionWindowHeight()/3))		||
			(p.x > (2*(double)viewManager.getResoultionWindowWidth()/3) &&
					p.y < ((double)viewManager.getResoultionWindowHeight()/3))	||
			(p.x < ((double)viewManager.getResoultionWindowWidth()/3) &&
					p.y > (2*(double)viewManager.getResoultionWindowHeight()/3))||
			(p.x >(2*(double)viewManager.getResoultionWindowWidth()/3) &&
					p.y > (2*(double)viewManager.getResoultionWindowHeight()/3))){
				//System.out.println("r");
				transformationType=TRANSFORMATION_ROTATE;
		}else if 
		   ((p.x > ((double)viewManager.getResoultionWindowWidth()/3) &&
			 p.x < (2*(double)viewManager.getResoultionWindowWidth()/3) &&
			 p.y < ((double)viewManager.getResoultionWindowHeight()/3)) ||
			(p.y > ((double)viewManager.getResoultionWindowHeight()/3) &&
			 p.y < (2*(double)viewManager.getResoultionWindowHeight()/3) &&
			 p.x < ((double)viewManager.getResoultionWindowWidth()/3))|| 
			(p.x > ((double)viewManager.getResoultionWindowWidth()/3) &&
			 p.x < (2*(double)viewManager.getResoultionWindowWidth()/3) &&
			 p.y > (2*(double)viewManager.getResoultionWindowHeight()/3))||
			(p.y > ((double)viewManager.getResoultionWindowHeight()/3) &&
			 p.y < (2*(double)viewManager.getResoultionWindowHeight()/3) &&
			 p.x > (2*(double)viewManager.getResoultionWindowWidth()/3))){
				//System.out.println("s");
				transformationType=TRANSFORMATION_SCALE;				
		}else{
			transformationType=TRANSFORMATION_TRANSLATE;
			//System.out.println("t");
			
		}
			
		
	}


	@Override
	public void mouseReleased(MouseEvent e) {
		transformationManager.addTempTranformationMatixToOverallTransformation();
		transformationType=TRANSFORMATION_NONE;
		mousePointClicked=null;
		
		//do transformation
		if (drawLine){
			transformationManager.reflectOverALine( linePointStart, linePointEnd);

			linePointEnd=null;
			linePointStart=null;
			drawLine=false;
		}
		
		repaint();
	}

	@Override
	public void keyPressed(KeyEvent e) {
		
		if (e.getKeyCode()== 17){
			this.drawLine=true;
			
		}
			
		
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
		this.drawLine=false;
		
		
	}

	@Override
	public void keyTyped(KeyEvent e) {
		char k = e.getKeyChar();
		switch (k) {
		case 'l':
		case 'L':
			try {
				loadNewFiles();
				
				buildScreen();
				repaint();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			break;
		case 'r':
		case 'R':
			transformationManager.resetTranformationMatix();
			repaint();
			break;
		case 'C':
		case 'c':
			toggleCiping = !toggleCiping;
			repaint();
			break;
		case 'q':
		case 'Q':
			System.exit(0);
		default:
			break;
		}
		
	}

	private void loadNewFiles()  throws IOException{
		JFileChooser fc = new JFileChooser();
		//In response to a button click:
		int r=fc.showOpenDialog(this);

		if (r!=0)
			return;
		File fileName = fc.getSelectedFile();
		if (fileName.getName().endsWith(".scn"))
			sceneManger.init(fileName.toString());
		else if (fileName.getName().endsWith(".viw")){
			viewManager.init(fileName.toString());
			//this.getParent().setSize(viewManager.getResoultionWindowWidth()+Constants.FRAM_POSITION*2, viewManager.getResoultionWindowHeight()+Constants.FRAM_POSITION*2);
			setSize(viewManager.getResoultionWindowWidth()+Constants.FRAM_POSITION*2, viewManager.getResoultionWindowHeight()+Constants.FRAM_POSITION*2);
			Frame f = ((Frame)this.getParent());
			
			f.setVisible(false);
			f.pack();
			f.setVisible(true);
		}
		transformationManager = new TransformationManager();
		
		
	}

}